﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Management;
using System.ComponentModel;
using System.Runtime.InteropServices;

namespace TestUSB
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        // lights on by default
        bool rOn = true;
        bool gOn = true;

        // are we connected to a device?
        bool deviceInstantiated = false;

        // connectionLabel strings
        String connected = "Device Connected!";
        String disconencted = "Device disconnected.";

        // watches for new USB connections
        ManagementEventWatcher cWatcher = new ManagementEventWatcher();
        ManagementEventWatcher rWatcher = new ManagementEventWatcher();

        // instantiate a device class to connect to devices
        UsbDevice device = new UsbDevice();

        // report buffer to send to the device when connected
        // [0] = reportID, [1] = light to toggle (1 or 2)
        byte[] buffer = new byte[2];
        byte[] inBuffer;
        ushort inSize;
        byte errCodes;

        public MainWindow()
        {
            InitializeComponent();

            // buffer[0] = report ID
            buffer[0] = 2;

            // Check for the device being connected already
            try
            {
                // No device connected yet
                if (!deviceInstantiated)
                {
                    // Check if a device matching our vid & pid exists
                    if (device.getDevices() != 0)
                    {
                        // Open a connection to the device
                        device.openDevice();

                        // We're now connected to a device
                        deviceInstantiated = true;
                        connectionLabel.Content = connected;
                        inSize = device.getMaxInput();
                        inBuffer = new byte[inSize];
//                        device.getInterrupt(inBuffer);
//                        setInputBlock();
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("An error occured: " + ex.Message);
            }

            // Watch for the device being disconnected
            WqlEventQuery rQuery = new WqlEventQuery();
            rQuery.EventClassName = "__InstanceDeletionEvent";
            rQuery.Condition = "TargetInstance ISA 'Win32_USBControllerDevice'";
            rQuery.WithinInterval = new TimeSpan(0, 0, 1);
            rWatcher.Query = rQuery;
            // Method call when device disconnected
            rWatcher.EventArrived += new EventArrivedEventHandler(rWatcher_EventArrived);
            rWatcher.Start();

            // Watch for the device being connected
            WqlEventQuery query = new WqlEventQuery();
            query.EventClassName = "__InstanceCreationEvent";
            query.Condition = "TargetInstance ISA 'Win32_USBControllerDevice'";
            query.WithinInterval = new TimeSpan(0, 0, 1);
            cWatcher.Query = query;
            // Method call when device connected
            cWatcher.EventArrived += new EventArrivedEventHandler(HandleEvent);
            cWatcher.Start();
        }

        // Device disconnected
        void rWatcher_EventArrived(object sender, EventArrivedEventArgs e)
        {
            // If it's our device:
            if (device.getDevices() == 0)
            {
                // Device has been removed
                deviceInstantiated = false;

                // Reset buttons
                redButton.Dispatcher.Invoke(
                    System.Windows.Threading.DispatcherPriority.Normal,
                    new Action(
                        delegate()
                        {
                            redButton.Content = "On";
                        }
                ));
                rOn = true;
                greenButton.Dispatcher.Invoke(
                    System.Windows.Threading.DispatcherPriority.Normal,
                    new Action(
                        delegate()
                        {
                            greenButton.Content = "On";
                        }
                ));
                gOn = true;

                // Indicate device is disconnected
                connectionLabel.Dispatcher.Invoke(
                    System.Windows.Threading.DispatcherPriority.Normal,
                    new Action(
                        delegate()
                        {
                            connectionLabel.Content = disconencted;
                        }
                ));
            }
        }

        private void setInputBlock()
        {
            StringBuilder buffString = new StringBuilder();
            System.Text.UTF8Encoding encoder = new System.Text.UTF8Encoding();
            inputBlock.Dispatcher.Invoke(
                System.Windows.Threading.DispatcherPriority.Normal,
                    new Action(
                        delegate()
                        {
                            foreach (byte b in inBuffer)
                            {
                                buffString.Append(b.ToString());
                            }
                            //inputBlock.Text = encoder.GetString(inBuffer);
                            inputBlock.Text = buffString.ToString();
                        }
            ));
        }

        // Occurs whenever user clicks the red button
        private void redButton_Click(object sender, RoutedEventArgs e)
        {
            // Only do stuff if a device is connected
            if (deviceInstantiated)
            {
                // buffer[1] = light to toggle
                buffer[1] = 1;
                // Light is on, turn it off
                if (rOn)
                {
                    // Change button display
                    redButton.Content = "Off";
                    rOn = false;
                    // send the report to the device
                    errCodes = device.sendInterrupt(buffer);
                    errorCode.Dispatcher.Invoke(
                        System.Windows.Threading.DispatcherPriority.Normal,
                            new Action(
                            delegate()
                            {
                                errorCode.Content = errCodes;
                            }
                    ));
                }
                // Light is off, turn it on
                else
                {
                    // Change button display
                    redButton.Content = "On";
                    rOn = true;
                    // send the report to the device
                    errCodes = device.sendInterrupt(buffer);
                    errorCode.Dispatcher.Invoke(
                        System.Windows.Threading.DispatcherPriority.Normal,
                            new Action(
                            delegate()
                            {
                                errorCode.Content = errCodes;
                            }
                    ));
                }
                device.getInterrupt(inBuffer);
                setInputBlock();
            }
        }

        // Occurs whenever user clicks the green button
        private void greenButton_Click(object sender, RoutedEventArgs e)
        {
            // Only do stuff if a device is connected
            if (deviceInstantiated)
            {
                // buffer[1] = light to toggle
                buffer[1] = 2;
                // Light is on, turn it off
                if (gOn)
                {
                    // Change button display
                    greenButton.Content = "Off";
                    gOn = false;
                    // send the report to the device
                    errCodes = device.sendInterrupt(buffer);
                    errorCode.Dispatcher.Invoke(
                        System.Windows.Threading.DispatcherPriority.Normal,
                            new Action(
                            delegate()
                            {
                                errorCode.Content = errCodes;
                            }
                    ));
                }
                // Light is off, turn it on
                else
                {
                    // Change button display
                    greenButton.Content = "On";
                    gOn = true;
                    // send the report to the device
                    errCodes = device.sendInterrupt(buffer);
                    errorCode.Dispatcher.Invoke(
                        System.Windows.Threading.DispatcherPriority.Normal,
                            new Action(
                            delegate()
                            {
                                errorCode.Content = errCodes;
                            }
                    ));
                }
                device.getInterrupt(inBuffer);
                setInputBlock();
            }
        }

        // Initialize search for device upon usb connection
        private void HandleEvent(object sender, EventArrivedEventArgs e)
        {
            try
            {
                // No device connected yet
                if (!deviceInstantiated)
                {
                    // If a device matching our vid/pid exists
                    if (device.getDevices() != 0)
                    {
                        // Open a connection to the device
                        device.openDevice();
                        // We're now connected to a device
                        deviceInstantiated = true;
                        // Indicate device is connected
                        connectionLabel.Dispatcher.Invoke(
                            System.Windows.Threading.DispatcherPriority.Normal,
                            new Action(
                                delegate()
                                {
                                    connectionLabel.Content = connected;
                                }
                        ));
                        inSize = device.getMaxInput();
                        inBuffer = new byte[inSize];
                        device.getInterrupt(inBuffer);
                        setInputBlock();
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("An error occured: " + ex.Message);
            }
        }

        // Program closing, final cleanup occurs
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            // Stop listening for USB events and close our device connection
            cWatcher.Stop();
            rWatcher.Stop();
            // Currently connected to a device
            if (deviceInstantiated)
            {
                // Close our connection to that device
                device.close();
                deviceInstantiated = false;
            }
        }
    }
}
